# -*-  coding: UTF-8  -*-

import wx, wx.xrc, wx.calendar
from wx import html # possible bug ?
import time, datetime, calendar
import re

import cfg, db, mgr
import wndraiser as wr
import xrcmgr

class MyFrame(wx.Frame, xrcmgr.Frame) :

    ATTRIBUTES = ['lstDay', 'lstMonth', 'lstYear', 'calendar']

    def __init__(self, parent) :
        xrcmgr.Frame.__init__(self, parent, 'MyFrame', self.ATTRIBUTES)

        # TaskbarIcon
        icon = wx.EmptyIcon()
        icon.CopyFromBitmap(wx.Bitmap("res/activities.xpm", wx.BITMAP_TYPE_ANY))
        self.SetIcon(icon)
        self.taskbar = wx.TaskBarIcon()
        self.taskbar.SetIcon(icon, 'pyActivities')

        # Timer
        self.timer = wx.Timer(self)

        # Create attributes
        self.dlgAsk = AskDialog(self)

        self.lstDay.InsertColumn(0, 'When')
        self.lstDay.InsertColumn(1, 'Activity')
        self.lstMonth.InsertColumn(0, 'Activity')
        self.lstMonth.InsertColumn(1, 'Nb')
        self.lstYear.InsertColumn(0, 'Activity')
        self.lstYear.InsertColumn(1, 'Nb')

        # Bind events
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
        self.Bind(wx.calendar.EVT_CALENDAR_SEL_CHANGED, self.OnDateChanged, self.calendar)
        self.Bind(wx.calendar.EVT_CALENDAR, self.OnDateDClick, self.calendar)
        self.Bind(wx.EVT_MENU, self.OnArchive, id=self.XRCID('menuArchive'))
        self.Bind(wx.EVT_MENU, self.OnExit, id=self.XRCID('menuExit'))
        self.Bind(wx.EVT_MENU, self.OnBalance, id=self.XRCID('menuBalance'))
        self.Bind(wx.EVT_MENU, self.OnPreferences, id=self.XRCID('menuPreferences'))
        wx.EVT_TASKBAR_LEFT_DCLICK(self.taskbar, self.OnTaskBarDClick)

        self.UpdateCalendar()
        self.__StartAsking()


    def OnTaskBarDClick(self, event) :
        if not self.IsShown() :
            self.Show()
        self.Raise()

    def __StartAsking(self) :
        self.OnTimer(wx.TimerEvent())
        self.timer.Start(cfg.GetInterval() * 1000 * 60)

    def __StopAsking(self) :
        self.timer.Stop()

    def OnTimer(self, event) :
       when = mgr.MustAsk( datetime.datetime.now() )
       if when :
            self.dlgAsk.Ask(when)

    def OnClose(self, event) :
        self.Hide()

    def OnExit(self, event) :
        if wx.MessageBox('Do you really want to quit ?', 'Confirm', wx.YES_NO) == wx.YES :
            self.__StopAsking()
            self.taskbar.Destroy()
            self.Destroy()

    def OnArchive(self, event) :
        print "OnArchive()"
        self.dlgAsk.Hide()
        self.__StopAsking()
        dlg = ArchiveDialog(self)
        dlg.ShowModal()
        self.__StartAsking()

    def OnBalance(self, event) :
        self.dlgAsk.Hide()
        self.__StopAsking()
        dlg = BalanceDialog(self)
        dlg.ShowModal()
        self.__StartAsking()

    def OnPreferences(self, event) :
        self.dlgAsk.Hide()
        self.__StopAsking()
        dlg = PreferencesDialog(self)
        dlg.ShowModal()
        self.__StartAsking()

    def OnDateChanged(self, event) :
        d = event.GetDate().FormatISODate()
        self.UpdateCalendar(d)

    def OnDateDClick(self, event) :
##        self.__StopAsking()
        d = event.GetDate().FormatISODate()
        existingWhen = [a.when for a in mgr.GetActivitiesByDay(d)]
        when = [(d, w) for w in range(len(cfg.GetWhen())) if not w in existingWhen]
        dlg = AskDayDialog(self)
        dlg.Ask(d, when)
##        self.__StartAsking()

    def UpdateCalendar(self, d = None) :
        if not d :
            d = self.calendar.GetDate().FormatISODate()
        dt = db.Sql2DT(d).date()

        # Calendar
        activities = { }
        for a in mgr.GetActivitiesByMonth(d) :
            activities[a.date] = activities[a.date] + 1 if a.date in activities else 1
        for day in range(1, calendar.monthrange(dt.year, dt.month)[1] + 1) :
            self.calendar.ResetAttr(day)
            cd = dt.replace(day=day)
            colour = wx.BLACK
            border = wx.calendar.CAL_BORDER_SQUARE if cd == datetime.date.today() else wx.calendar.CAL_BORDER_NONE
            if cd.isoformat() in activities :
                colour = wx.GREEN if activities[cd.isoformat()] == 4 else wx.RED
            self.calendar.SetAttr(cd.day, wx.calendar.CalendarDateAttr(colour, border = border))
        self.calendar.Refresh()

        # By day
        activities = mgr.GetActivitiesByDay(d)
        self.lstDay.DeleteAllItems()
        activities.reverse()
        for a in activities :
           idx = self.lstDay.InsertStringItem(0, cfg.GetWhen(a.when))
           self.lstDay.SetStringItem(idx, 1, a.activity)

        # By Month
        bilan = mgr.GetBilanByMonth(d)
        self.lstMonth.DeleteAllItems()
        for a in reversed(bilan) :
           idx = self.lstMonth.InsertStringItem(0, a.activity)
           self.lstMonth.SetStringItem(idx, 1, str(a.nb))

        # By Year
        bilan = mgr.GetBilanByYear(d)
        self.lstYear.DeleteAllItems()
        for a in reversed(bilan) :
           idx = self.lstYear.InsertStringItem(0, a.activity)
           self.lstYear.SetStringItem(idx, 1, str(a.nb))


class AskDialog(wx.Dialog, xrcmgr.Dialog) :

    def __init__(self, parent) :
        xrcmgr.Dialog.__init__(self, parent, 'AskDialog', ['lstActivity', 'lstWhen'])

       # attributes
        self.lstWhen.InsertColumn(0, 'Date')
        self.lstWhen.InsertColumn(1, 'Time')

        self.current = []
        for a in mgr.GetAllActivitiesName() :
            self.lstActivity.Append(a)

        # Bind events
        self.Bind(wx.EVT_BUTTON, self.OnApply, wx.xrc.XRCCTRL(self, 'btnApply'))

    def OnApply(self, event) :
        a = self.lstActivity.GetValue()
        if not a : return  # We don't want blank activity

        if self.lstActivity.FindString(a) == wx.NOT_FOUND :
            self.lstActivity.Append(a)

        self.lstWhen.Freeze()
        sel = [i for i in range(len(self.current)) if self.lstWhen.GetItemState(i, wx.LIST_STATE_SELECTED) == wx.LIST_STATE_SELECTED]
        for i in reversed(sel) :
            d, t = self.current[i]
            # TODO : verify that index(t) exists
            if mgr.AddActivity(d, t, a) :
                del self.current[i]
                self.lstWhen.DeleteItem(i)
        self.lstWhen.Thaw()

        if sel :
            self.GetParent().UpdateCalendar()

        if not self.current :
            self.Hide()

    def Ask(self, when) :
        self.current = []
        self.lstWhen.DeleteAllItems()
        for i, data in enumerate(when) :
            self.current.append(data)
            idx = self.lstWhen.InsertStringItem(self.lstWhen.GetItemCount(), data[0])
            self.lstWhen.SetStringItem(idx, 1, cfg.GetWhen(data[1]))
        thread = wr.wxWindowRaiserThread(self, True)
        thread.start()

class AskDayDialog(wx.Dialog, xrcmgr.Dialog) :

    def __init__(self, parent) :
        xrcmgr.Dialog.__init__(self, parent, 'AskDialog', ['lstWhen', 'lstActivity'])

        # Bind events
        self.Bind(wx.EVT_BUTTON, self.OnApply, wx.xrc.XRCCTRL(self, 'btnApply'))

    def OnApply(self, event) :
        print "AskDayDialog.OnApply : TODO"
        self.EndModal(wx.OK)

    def Ask(self, day, when) :
        print "AskDayDialog.Ask(%s, %s)" %(str(day), str(when))
        self.SetTitle(str(day))
        self.ShowModal()

class PreferencesDialog(wx.Dialog, xrcmgr.Dialog) :

    reTime = re.compile('([1-9]|[0-1][0-9]|2[0-3]):[0-5][0-9]') # match HH:MM

    def __init__(self, parent) :
        xrcmgr.Dialog.__init__(self, parent, 'PreferencesDialog', ['editInterval', 'listWhen', 'listHolidays', 'dpHoliday'])
        self.editInterval.SetValue(str(cfg.GetInterval()))
        self.__UpdateHolidays()
        self.__UpdateWhens()

        # Bind events
        self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnDClickListWhen, self.listWhen)
        self.Bind(wx.EVT_BUTTON, self.OnAddHoliday, wx.xrc.XRCCTRL(self, 'btnAddHoliday'))
        self.Bind(wx.EVT_BUTTON, self.OnOk, wx.xrc.XRCCTRL(self, 'wxID_OK'))

    def __UpdateHolidays(self) :
        holidays = mgr.GetAllHolidays()
        self.listHolidays.Clear()
        for h in holidays :
            self.listHolidays.Append(h)

    def __UpdateWhens(self) :
        for w in cfg.GetWhen() :
            self.listWhen.Append(w)

    def OnOk(self, event) :
        """Save configuration"""
        cfg.SetInterval(int(self.editInterval.GetValue()))
        self.EndModal(wx.OK)

    def OnDClickListWhen(self, event) :
        oldWhen = event.GetString()
        when = wx.GetTextFromUser("When do you want to be asked :", "Change time to ask", oldWhen)
        if when != oldWhen and self.reTime.match(when) and not when in cfg.GetWhen() :
            self.listWhen.SetString(event.GetSelection(), when)
            cfg.SetWhen(cfg.GetWhen().index(oldWhen), when)

    def OnAddHoliday(self, event) :
        d = self.dpHoliday.GetValue().FormatISODate()
        mgr.InsertHoliday(d)
        self.__UpdateHolidays()


class ArchiveDialog(wx.Dialog, xrcmgr.Dialog) :

    def __init__(self, parent) :
        xrcmgr.Dialog.__init__(self, parent, 'ArchiveDialog', ['archiveFilePicker', 'datePickerFrom', 'datePickerTo', 'cbRemoveOldActivities'])

        # Bind events
        self.Bind(wx.EVT_BUTTON, self.OnArchive, wx.xrc.XRCCTRL(self, 'btnArchive'))

    def OnArchive(self, event) :
        filename = self.filePick.GetPath()
        if not filename :
            wx.MessageBox("You must select a file")
            return

        fromDate, toDate = self.fromDate.GetValue().FormatISODate(), self.toDate.GetValue().FormatISODate()
        if fromDate > toDate :
            wx.MessageBox("'From date' must be earlier than 'to date'")
            return

        mgr.Archive(filename, fromDate, toDate, self.cbDelAct.GetValue())
        self.EndModal(wx.OK)


class BalanceDialog(wx.Dialog, xrcmgr.Dialog) :

    __HEADER = """
    <html>
    <head>
      <title>Balance</title>
    </head>
    <body>
    <h1>Balance<h1>
    """

    __FOOTER = """
    </body>
    </htm>
    """

    def __init__(self, parent) :
        xrcmgr.Dialog.__init__(self, parent, 'BalanceDialog', ['htmlWindow'])
        self.CreateBalance()

    def CreateBalance(self) :
        self.htmlWnd.AppendToPage(self.__HEADER)

        # By Month
        self.htmlWnd.AppendToPage("<h2>Balance by month</h2>")
        self.htmlWnd.AppendToPage("<ul>")
        for a in mgr.GetBilanByMonth(str(datetime.date.today())) :
            self.htmlWnd.AppendToPage("<li>%s : %d hours</li>" % (a['activity'], a['nb']))
        self.htmlWnd.AppendToPage("</ul>")

        self.htmlWnd.AppendToPage(self.__FOOTER)
